// pkd.c

#include <ansi.h>
#include <localtime.h>

inherit F_DBASE;

#define ENTRY_ROOM "/d/pk/entry"
#define READY_ROOM "/d/pk/ready"
#define PK_ROOM    "/d/pk/turen"

// the state of daemon
nosave int state;

#define SLEEPING 0
#define GET_READY 1
#define STARTING 2

#define GET_READY_TIME 180

nosave object *total = ({});
nosave int ready_time = 0;

// 四次比赛列表
nosave mapping *tlist = ({
    ([
        "name":"屠人热身赛",
        "time":({1800, 1810,}),
        "exp":({100000, 500000}),
        "last_day":0,
    ]),
    ([
        "name":"屠人准备赛",
        "time":({1900, 1910,}),
        "exp":({100000, 2000000}),
        "last_day":0,
    ]),
    ([
        "name":"屠人选拔赛",
        "time":({2000, 2010,}),
        "exp":({100000, 5000000}),
        "last_day":0,
    ]),
    ([
        "name":"屠人大赛",
        "time":({2100, 2110}),
        "exp":({100000, 2000000000}),
        "last_day":0,
    ])
});

nosave int selected;

private void change_state(int new_state);
private void init_player(object me);
private int start_competition();
private void message_competition(string msg);
private void auto_check();
private void give_bouns(object me);
private void kickout_players();
private void restore_status(object me);
private void send_invite_message();

// 外部可调用的函数
int check_out(object me);

// return the time of prompt
int is_pking() { return state == STARTING; }
int is_ready() { return state == GET_READY; }

void create()
{
    seteuid(ROOT_UID);
    set("channel_id", "比赛精灵");
    // write("比赛精灵已经启动。\n");
    CHANNEL_D->do_channel(this_object(), "sys", "比赛精灵已经启动。");
    state = SLEEPING;
    set_heart_beat(30);
}

int clean_up()
{
    return 1;
}

// join in competition
int join_competition(object ob)
{
    if (state != SLEEPING)
        return notify_fail("现在屠人场正在举行活动，你还是等等再说吧。\n");

    if (ob->query("combat_exp") < 800000 && !ob->query_temp("team_fight"))
        return notify_fail("你这点本事就别进去啦。\n");

    if (ob->query_condition())
        return notify_fail("你现在状态不佳，还是别进去了。\n");

    if (!arrayp(total))
        total = ({ob});
    else if (member_array(ob, total) == -1)
        total += ({ob});

    message_competition((ultrap(ob) ? "大宗师" : "") +
                        ob->name(1) + "进入屠人场。");

    init_player(ob);
    set_heart_beat(1);
    return 1;
}

// scan
private void heart_beat()
{
    mixed lt;
    int ti;
    int i;
    int last_day;

    seteuid(ROOT_UID);
    lt = localtime(time());
    ti = lt[LT_HOUR] * 100 + lt[LT_MIN];
    // 仅在周日举行
    if (lt[LT_WDAY])
        return;

    switch (state)
    {
    case SLEEPING:
        last_day = time() / 86400;
        for (i = 0; i < sizeof(tlist); i++)
        {
            if (ti < tlist[i]["time"][0] || ti > tlist[i]["time"][1])
                // not change state
                continue;
            if (last_day == tlist[i]["last_day"])
                // this day has do it
                break;
            tlist[i]["last_day"] = last_day;
            selected = i;

            // chanage state to "GET_READY";
            change_state(GET_READY);
            break;
        }
        break;

    case GET_READY:
        if (time() < ready_time + GET_READY_TIME)
            break;

        // change state to "GET_READY_2";
        change_state(STARTING);
        break;

    case STARTING:
        break;
    }

    if (sizeof(total))
        auto_check();
}

// the daemon change to a new state
private void change_state(int new_state)
{
    // mixed lt = localtime(time());
    int n;

    switch (new_state)
    {
    case GET_READY:
        // kickout the player now in competition
        kickout_players();

        ready_time = time();
        message_competition("听说一年一度的" + tlist[selected]["name"] + "马上就要"
                            "举行了，不知道今年的冠军是谁？");
        set_heart_beat(1);
        send_invite_message();
        break;

    case STARTING:
        if (!(n = start_competition()))
        {
            message_competition("听说今年的" + tlist[selected]["name"] + "因故"
                                "取消了，真是没劲。");
            new_state = SLEEPING;
        }
        else
        {
            message_competition("听说今年的" + tlist[selected]["name"] +
                                "吸引了" + chinese_number(n) +
                                "名高手！走...看看热闹去。");
            set_heart_beat(1);
        }
        break;

    default:
        total = ({});
        break;
    }

    // change to new state
    state = new_state;
    if (state == SLEEPING)
        set_heart_beat(30);
    return;
}

// set player's override functions
private void init_player(object me)
{
    tell_object(me, HIY "你眼前忽然一花……\n" NOR);
    me->set_override("unconcious", (: call_other, __FILE__, "check_out" :));
    me->set_override("die", (: call_other, __FILE__, "check_out" :));
    me->set_override("quit", (: call_other, __FILE__, "check_quit" :));
    me->set_temp("backup/killer", me->query_killer());
    me->set_temp("backup/want", me->query_want());

    me->move(sprintf(PK_ROOM "%d", random(12) + 1));
    tell_object(me, HIY "你定神一看，这才发现自己已经到了" +
                        environment(me)->short() + HIY "。\n");
    me->set("backup/condition", me->query_condition());
    me->clear_condition();
}

// kickout the players in competition when formal competition
// get ready
private void kickout_players()
{
    object ob;
    string room;
    mapping my;

    if (!arrayp(total))
        return;

    foreach (ob in total)
    {
        if (!objectp(ob))
            continue;
        room = base_name(environment(ob));
        if (!sscanf(room, PK_ROOM "%*s"))
            // not in pk room
            continue;

        my = ob->query_entire_dbase();
        my["eff_qi"] = my["max_qi"];
        my["eff_jing"] = my["max_jing"];
        my["qi"] = 1;
        my["jing"] = 1;

        tell_object(ob, HIC "\n乌老大走了过来，嚷嚷道：“清场了！清场了，都快走吧！”\n" NOR);

        restore_status(ob);
        ob->move(ENTRY_ROOM);
        message("vision", "只见" + ob->name() + "悻悻的走了出来。\n",
                environment(ob), ({ob}));
        if (!living(ob))
            ob->revive();
    }
}

// start competition, overide all the player's unconcios/die
// function
private int start_competition()
{
    object env;
    object *obs;
    int i;

    env = find_object(READY_ROOM);
    if (!objectp(env))
        return 0;

    obs = filter_array(all_inventory(env), (: userp($1) && !wizardp($1) :));
    if (sizeof(obs) < 2)
        return 0;

    if (sizeof(obs) == 2)
    {
        if (obs[0]->query("couple/id") == obs[1]->query("id"))
        {
            message_vision("乌老大在外面喊道：“就你们夫妻"
                           "俩个参加？还是算了吧。”\n",
                           obs[0]);
            return 0;
        }
    }

    message("vision", "一个黑影走了过来，打开"
                      "了门，冷冷道：“都进去吧！”\n",
            env);

    for (i = 0; i < sizeof(obs); i++)
    {
        reset_eval_cost();
        init_player(obs[i]);
        // 记录参赛次数
        obs[i]->add("state/pk", 1);
    }

    set_heart_beat(1);
    message("vision", HIG "屠人比赛已经开始，快动手吧！\n", obs);
    return sizeof(total = obs);
}

// send message out
private void message_competition(string msg)
{
    CHANNEL_D->do_channel(this_object(), "rumor", msg);
}

// check all the players who join the competition
private void auto_check()
{
    object ob;
    string msg;
    string room;
    object *lost;
    int i;

    lost = ({});
    for (i = 0; i < sizeof(total); i++)
    {
        if (!objectp(total[i]))
            continue;
        room = base_name(environment(total[i]));
        if (!sscanf(room, PK_ROOM "%*s"))
        {
            // not in pk room
            restore_status(total[i]);
            total[i] = 0;
        }
        if (total[i]->query("qi") < 1 || total[i]->query("jing") < 1)
            lost += ({total[i]});
    }

    // kickout the players who lost competition
    foreach (ob in lost)
        check_out(ob);

    total -= ({0});
    if (state == SLEEPING)
    {
        if (sizeof(total) < 1)
            // end of competition. call the change_state
            // function to restore the normal heart beat.
            change_state(SLEEPING);

        return;
    }

    if (state != STARTING)
        return;

    if (sizeof(total) < 1)
    {
        msg = "听说屠人大赛参赛者死的死，逃的逃，现在一个人都没有啦！";
    }
    else if (sizeof(total) == 1)
    {
        // change the daemon's state
        msg = "听说本次屠人大赛圆满结束，" +
              total[0]->name(1) + "成为屠人冠军！";
        give_bouns(total[0]);
    }
    else if (sizeof(total) == 2 && total[0]->query("couple/id") == total[1]->query("id"))
    {
        msg = "听说本次屠人大赛圆满结束，" +
              total[0]->name(1) + "和" + total[1]->name(1) +
              "夫妻双双把家还。";
        give_bouns(total[0]);
        give_bouns(total[1]);
    }
    else
        return;

    message_competition(msg);
    change_state(SLEEPING);
}

private void give_bouns(object me)
{
    int exp;
    int pot;
    string msg;

    // lead me out
    restore_status(me);
    tell_object(me, "这次真是爽呆了……\n");
    me->move(ENTRY_ROOM);
    message("vision", me->name() + "慢慢的走了过来，一脸奸笑。\n",
            environment(me), ({me}));

    // bouns
    pot = me->query_potential_limit();
    pot -= me->query("potential");
    exp = me->query("combat_exp") / 500 + 3000;
    msg = HIG "通过这次大赛，你获得了 " + (string)exp + " 点经验";
    if (pot > 0)
    {
        pot = random(pot) * 10 + 1000;
        msg += "和 " + (string)pot + " 点潜能。\n" NOR;
    }
    else
    {
        pot = 0;
        msg += "。\n" NOR;
    }
    me->add("potential", pot);
    me->add("combat_exp", exp);
    // 记录PK胜利次数
    me->add("state/pk_win", 1);
    tell_object(me, msg);
}

// remove overide function
// restore condition
private void restore_status(object me)
{
    mapping cnd;
    string *ks;
    int i;

    me->delete_override("unconcious");
    me->delete_override("die");
    me->delete_override("quit");
    me->remove_all_enemy(1);
    me->remove_all_killer();
    me->clear_condition();
    me->receive_damage("qi", 0);
    me->apply_killer(me->query_temp("backup/killer"));
    me->apply_want(me->query_temp("backup/want"));

    cnd = me->query("backup/condition");
    me->delete ("backup/condition");
    me->delete_temp("block_msg/all");
    if (!mapp(cnd))
        return;
    ks = keys(cnd);
    for (i = 0; i < sizeof(ks); i++)
        me->apply_condition(ks[i], cnd[ks[i]]);
}

// send invite message
private void send_invite_message()
{
    object *obs;
    int exp_ul, exp_dl;

    exp_dl = tlist[selected]["exp"][0];
    exp_ul = tlist[selected]["exp"][1];
    obs = filter_array(all_interactive(),
                       (: !wizardp($1) &&
                          $1->query("combat_exp") >= $(exp_dl) &&
                          $1->query("combat_exp") <= $(exp_ul)
                       :));
    if (!sizeof(obs))
        return;

    message("vision", HIR "你收到了乌老大撒下的武林盟帖，邀请你参加这次" + tlist[selected]["name"] + "，有没有兴趣去显显身手？\n" NOR,
            obs);
}

int start_by_others(int n)
{
    if (state == STARTING)
        return notify_fail("现在比赛正在进行中。\n");

    if (state == GET_READY)
        return notify_fail("现在比赛正在报名中。\n");

    if (n < 0 || n >= sizeof(tlist))
        return notify_fail("没有这个等级的比赛(0-" + (sizeof(tlist) - 1) + ")。\n");
    selected = n;
    change_state(GET_READY);
    return 1;
}

object *query_all_competitor()
{
    return total;
}

// overide function of quit
int check_quit(object me)
{
    message_competition("听说" + me->name(1) +
                        "临阵脱逃，溜走了。");
    restore_status(me);
    if (arrayp(total))
        total -= ({me});

    tell_object(me, "你逃出了屠人场。\n");

    // continue run quit function
    me->move(ENTRY_ROOM);
    message("vision", "只见" + me->name() + "慌里慌张的跑了出来。\n",
            environment(me), ({me}));
    return 1;
}

// overide function of lost(die/unconcious)
int check_out(object me)
{
    object ob;
    mapping my;
    string msg;
    string room;

    room = base_name(environment(me));
    if (!sscanf(room, PK_ROOM "%*s"))
    {
        // not in pk room
        total -= ({me});
        return 0;
    }

    my = me->query_entire_dbase();
    my["eff_qi"] = my["max_qi"];
    my["eff_jing"] = my["max_jing"];
    my["qi"] = 1;
    my["jing"] = 1;

    tell_object(me, HIR "\n你觉得眼前一阵模糊……这下完了！\n" NOR);
    if (ob = me->query_last_damage_from())
    {
        msg = "听说" + me->name(1) + "惨遭" + ob->name(1) + "的毒手，被无情淘汰。";
    }
    else
        msg = "听说" + me->name(1) + "运气不佳，本领有限、已经惨遭淘汰。";
    message_competition(msg);

    restore_status(me);
    total -= ({me});
    me->move(ENTRY_ROOM);
    message("vision", "一个黑影倏的窜了出来，随即就是“啪”的"
                      "一声，就见" +
                      me->name() + "摔倒了地上，一副半死不"
                      "活的样子。\n",
            environment(me), ({me}));
    tell_object(me, "半昏半迷中，你觉得被人拎了起来，又"
                    "重重的摔倒了地上。\n");
    if (!living(me))
        me->revive();
    return 1;
}

// reject_join?
string reject_join(object me)
{
    int exp;

    if (state == STARTING)
        return "现在" + tlist[selected]["name"] + "正在举行，"
               "你还是下次再来吧。";

    if (state != GET_READY)
        return "现在没要举行比赛啊？你跑来干什么？";

    exp = me->query("combat_exp");
    if (exp < tlist[selected]["exp"][0])
        return "你还是算了吧，你这点经验就别进去现眼了。";

    if (exp > tlist[selected]["exp"][1])
        return "哦…您武功如此高强，这次还是别和小辈们争了。";

    return 0;
}
